home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Everything For A Hacker
/
19990506-[HACK].iso
/
HEXEDIT
/
UTILS
/
80X0393.ARJ
/
ADLIB.TXT
next >
Wrap
Text File
|
1993-03-30
|
8KB
|
154 lines
By: Emil Gilliam
Re: adlib digitized sound
------------------------------------------------------------------------
Okay, here we go with some specifics on how to play digitized sound out
of the AdLib! Note: If you write a program that uses sound boards, you
should make it recognize the Sound Blaster and use the Sound Blaster DAC
if there is one, because it sounds better, so I suggest that you only
use this method for playing digitized sound out of the AdLib if there
actually is a real AdLib. (Also, I don't know if this method works
right on the Sound Blaster, so if there's a Sound Blaster, use the DAC
instead!!)
Here's how to play a digitized sample out of the AdLib:
1.) Disable interrupts. (While we change vectors and things)
2.) Get the old interrupt 8 vector and save it. Set the interrupt 8
vector to point to a new interrupt 8 handler (which is described below).
I suggest that you get and set interrupt vectors yourself instead of
calling DOS to do it, because maybe DOS tries to hook itself into every
vector somehow (?) and that can be a problem when our new interrupt 8
vector will be called thousands of times a second.
3.) Okay, now we're going to set up the AdLib for playing digitized
sound. As many of you know, the AdLib uses I/O ports 388h and 389h (388h
is the index register, 389h is the data, and 389h is write-only).
Note: After you write a register number to port 388h, you need to wait
3.3 microseconds for the card to respond. After you write a value to
one of the registers at port 389h, you need to wait 23 microseconds
before you can write to another register. You can wait 3.3 microseconds
by doing 6 "IN AL,DX" instructions from port 388h, (I think that each IN
AL,DX from port 388h will take the same amount of time no matter what
the speed of the computer is [?] because it takes the card a while to
get the value of the status register of the AdLib, which is what you get
when you read from port 388h. But we don't need the value of that
status register, we just need to IN AL,DX from it 6 times for the 3.3
microsecond wait.) You can wait the 23 microseconds by doing 35 "IN
AL,DX" instructions from port 388h. By the way, you should put all
these IN AL,DX's in a row rather that in a loop, because the loop will
take time and you'll wait more time than necessary.
Here's how to set up the AdLib card for playing digitized sound. Write
21h to register 20h (Sets MULTI=1,AM=0,VIB=0,KSR=0,EG=1 for operator 1).
Then write 0F0h to register 60h (Sets attack rate to 15 and decay rate
to 0 for operator 1, makes sense because we want the sine wave to start
immediately and we never want it to stop), and write 0F0h to register 80h
(sets the sustain level to 15 and the release rate to 0 for operator 1).
Then, write 01h to register 0C0h. (Feedback=0 and Additive Synthesis is
on for voice 1 [which is operator 1 and operator 4]). Then write 0 to
register 0E0h. (Waveform=regular sine wave for operator 1.) Then write
3Fh to register 43h (sets total level=63 and attenuation for operator 4,
don't ask me why this is done, but I do know that operator 4 combines
with operator 1 to make one of the voices).
Then write 1 to register 0B0h.
Then write 8Fh to register 0A0h.
Then write 2Eh to register 0B0h. (Set KEY ON)
(I don't know why we have the multiple writes to register 0B0h.
This sets the frequency of operator 1, the speed of the sine wave.
4.) Immediately (right after writing 2Eh to register 0B0h, and
interrupts are still disabled), wait until 952h 8253 timer ticks have
passed. I think that what this does is wait for the sine wave being
generated by operator 1 to get all the way to the top.
5.) Now that the sine wave of operator 1 is at the top, we're immedia
tely going to change the frequency of operator 1 to 0, so that the sine
wave is stuck at the top. Write 20h to register 0B0h and write 0 to
register 0A0h. The 20h in register 0B0h keeps operator 1 in KEY-ON
state.
6.) We're almost done setting up. Divide 1193180 by the number of
samples per second and write that value into timer channel 0 (of the
8253 chip). This will change the number of times per second interrupt 8
is called to the number of samples per second. Interrupt 8 is going to
be called for each sample, and it will play one sample each time it's
called.
7.) Enable interrupts, and wait until the sample is done playing. (Your
interrupt 8 handler should set some sort of flag when it's done.)
8.) Disable interrupts, set the interrupt 8 vector to what it used to
be, write 0 to 8253 timer channel 0 (to make interrupt 8 go 18.2 times a
second), and we're done!
-----
Okay. The new interrupt 8 handler should do this.
1.) Save any used registers. (I know that the CPU will probably be in
the waiting loop when interrupt 8 is called, and the waiting loop might
use no registers, but save registers just to be on the safe side because
the CPU might be in the middle of processing a keyboard interrupt or
something like that.)
2.) Get a 6-bit sample from the digitized sound sample. (If you have an
8-bit sample, just shift each sample right two bits. I assume that'll
be the case because you can write a program to play digitized sound that
writes values to the Sound Blaster DAC if there is a Sound Blaster and
use this method if there is an AdLib.) Write that number to register
40h. (The top 2 bits should be 0).
Note: An alternative is to have the initialization code write 40h to
port 388h right before enabling interrupts, and then all that the
interrupt 8 handler has to do is write values to port 389h instead of
having to write 40h to port 388h every time.
3.) Write 20h to port 20h (8259 non-specific EOI), restore any used
registers, and get the heck outta there with IRET.
-----
The only problem with this is that the computer's clock will be held
while the sample is playing, because the regular interrupt 8 isn't
executing while the sample is playing, but if that's a problem you can
circumvent that yourself by getting the length of the sample and adding
that to the computer's time when you're done, or by possibly getting the
CMOS time. That's something I still don't know, on AT's does the
computer get the time from the CMOS whenever you have to get the time,
or does the computer just get the time on bootup and write that into
some low-memory address for interrupt 8 to increase every time it's
called? On AT's, does interrupt 8 even increase any time variables at
all? Does it need to? If anyone knows anything about that, please let
me know.
-----
The playing of digitized sound out of the AdLib doesn't have to use
operator 1, it can use any operator. It just has to use the same
operator all the way through. (Except for when you write 3Fh to
register 43h, don't ask me why that was in what I disassembled... but
if you change operator numbers, you'll have to change this reference to
operator 4 to the operator that the other one is "paired up with"...)
That means that you can play digitized sound and music at the same time
out of the AdLib! Just play digitized sound as usual and while waiting
for the sample to play, use the other voices to play music! You can
even play two samples at the same time by using two different operators
and having your interrupt 8 handler write values to both! Theoreti
cally, you can play as many samples as you want and music at the same
time... I'm sure that in practice that would be VERY hard to pull
off... almost more trouble than it's worth... but maybe someone should
give it a try!
And there you have it. I hope that THAT is pretty complete! But if
anyone still needs any more information, like on how to read or write to
the 8253 timer chip, let me know.
Emil Gilliam